<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Snake</title>
<script type="text/javascript">
    var worldSize = [400,300];
    var score = 0;
    var speed = 5;
    var bodySize = 5;
    var gameWorld;
    var painter;
    var moveOritention = [bodySize,0];
    var gameInterval;
    var foodInterval;
    var scoreRate;
    var inputReady;
    var Snake = {   //Snake class
        createNew : function() {
            var snake = {};    
            snake._head = [200, 150];
            snake._body = new Array([snake._head[0] - bodySize, snake._head[1]],[snake._head[0] - bodySize * 2, snake._head[1]]);
            return snake;
        }
    };
    var Food = {    //Food class
        createNew : function() {
            var food = {}; 
            var reCreate = false;
            var _foodX = Math.random()*(worldSize[0] - 5)+1;
            var _foodY = Math.random()*(worldSize[1] - 5)+1;
            
            do {
                reCreate = false;
                if (_foodX == snake._head[0] && _foodY == snake._head[1]) {
                    var _foodX = Math.random()*(worldSize[0] - 1)+1;
                    var _foodY = Math.random()*(worldSize[1] - 1)+1;
                    reCreate = true;
                }
                for (var i = 0; i < snake._body.length; i++) 
                if (_foodX == snake._body[i][0] && _foodY == snake._body[i][1]) {
                    var _foodX = Math.random()*(worldSize[0] - 1)+1;
                    var _foodY = Math.random()*(worldSize[1] - 1)+1;
                    reCreate = true;
                    break;
                }
            } while (reCreate);            
            food.pos = [_foodX,_foodY];
            food.existTime = 10000; //10 secs
            
            return food;
        }
    };
    
    var snake = Snake.createNew();
    var foods = new Array();
    
    function gameDisplay() {    //game main process
        
        //console.log(snake._head[0] + "," + snake._head[1]);
        gameWorld.focus();
        gameUpDate();
        drawGame();
    }
    
    function drawGame() {   //draw method, paint every thing in game
        painter.clearRect(0,0,worldSize[0],worldSize[1]);
        painter.fillStyle = "rgb(0,0,0)";
        painter.fillRect(snake._head[0],snake._head[1],bodySize,bodySize);  //Draw snake head
        painter.fillStyle = "rgb(0,0,255)";
        for (var i = 0; i < snake._body.length; i ++) { //Draw snake body
            painter.fillRect(snake._body[i][0],snake._body[i][1],bodySize,bodySize);
        }
        painter.fillStyle = "rgb(255,0,0)";
        for (var i = 0; i < foods.length; i++) {    //Draw food
            painter.fillRect(foods[i].pos[0],foods[i].pos[1],bodySize,bodySize);
        }
    }
    
    function foodCountDown() {  //TO REDUCE EVERY FOOD EXIST TIME 
        for (var i = 0; i < foods.length; i++) {
            foods[i].existTime -= 1;
            if (foods[i].existTime <= 0)
                foods.splice(i,1);
        }
        
        if (scoreRate > 0);
        scoreRate --;
    }
    
    function gameUpDate() { //update game status
        
        checkStatus();
        snakePositionChange();
    }
    
    function checkStatus() {    //check snake status and food amounts
        for (var i = 0; i < snake._body.length; i++) { // whether snake will eat itself
            if (snake._head[0] + moveOritention[0] == snake._body[i][0] 
                && snake._head[1] + moveOritention[1] == snake._body[i][1]) {
                gameOver();
                break;
            }
        }
        
        if (snake._head[0] < 0 || snake._head[0] > worldSize[0] - 5 || snake._head[1] < 0   //whether snake will crush wall
            || snake._head[1] > worldSize[1] - 5)
            gameOver();
        
        if (foods.length < 2) { //if food amouts less than 2
            createFood();
        }
    }

    function snakePositionChange() {
        
        var theLast = snake._body.length - 1;
        tempX = snake._body[theLast][0];
        tempY = snake._body[theLast][1];
        
        for (var i = theLast; i > 0; i--) {
            snake._body[i][0] = snake._body[i-1][0];
            snake._body[i][1] = snake._body[i-1][1];
        }
        
        snake._body[0][0] = snake._head[0];
        snake._body[0][1] = snake._head[1];
        snake._head[0] += moveOritention[0];
        snake._head[1] += moveOritention[1];
        
        for (var i = 0; i < foods.length; i++) {    //whether snake will eat food
            if (impactCheck(snake._head,foods[i].pos)) {
                snake._body.push([tempX,tempY]);
                score += Math.round(speed * 10 + (scoreRate/2000)*50);
                scoreRate = 2000;
                speed += 1;
                clearInterval(gameInterval);
                gameInterval = setInterval(gameDisplay,500/speed);
                foods.splice(i,1);
            }
        }
        
        inputReady = true;
    }
    
    function createFood() {
        foods.push(Food.createNew());
    }
    
    function impactCheck(source, target) {
        
        if (source[0] >= target[0] - bodySize && source[0] <= target[0] + bodySize 
           && source[1] >= target[1] - bodySize && source[1] <= target[1] + bodySize) {
            console.info(true)
            return true;
        }
        console.info(false);
        return false;
    }
    
    function gameOver() {
        clearInterval(gameInterval);
        clearInterval(foodInterval);
        alert("游戏结束，您的分数是" + score);
    }
    
    function keyPressEventHandler(e) {
        if (!inputReady)
            return;
        
        var keyID = e.keyCode ? e.keyCode :e.which;  
        if(keyID == 38 || keyID == 119)  { // up arrow and W  
            if (moveOritention[1] == 0) {
                moveOritention = [0,-bodySize];
                inputReady = false;
            }
            e.preventDefault();  
        }  
        if(keyID == 39 || keyID == 100)  { // right arrow and D  
            if (moveOritention[0] == 0) {
                moveOritention = [bodySize,0];
                inputReady = false;
            }
            e.preventDefault();  
        }  
        if(keyID == 40 || keyID == 115)  { // down arrow and S  
            if (moveOritention[1] == 0) {
                moveOritention = [0,bodySize];
                inputReady = false;
            }
            e.preventDefault();  
        }  
        if(keyID == 37 || keyID == 97)  { // left arrow and A  
            if (moveOritention[0] == 0) {
                moveOritention = [-bodySize,0]; 
                inputReady = false;
            }
            e.preventDefault();  
        }  
    }
    
    function init() {
        speed = 5;
        score = 0;
        scoreRate = 2000;
        snake = Snake.createNew();
        foods = new Array();
        moveOritention = [bodySize,0]
        gameWorld = document.getElementById("_gamerWorld");
        gameWorld.focus();
        worldSize[0] = gameWorld.width;
        worldSize[1] = gameWorld.height;
        painter = gameWorld.getContext("2d");
        gameWorld.addEventListener("keypress",keyPressEventHandler,true);
        createFood();
        //gameWorld.focus();
        drawGame();
        clearInterval(gameInterval);
        clearInterval(foodInterval);
        gameInterval = setInterval(gameDisplay,500/speed);    //game main process begin
        foodInterval = setInterval(foodCountDown,1);
    }
</script>
</head>
<body>
    <canvas height="300" width="400" id="_gamerWorld" tabindex="0" style="border:1px solid #c3c3c3;">
    </canvas>
    <br/>
    <button onclick="init()">开始游戏</button><br/>
    控制方向WASD或↑↓←→
    
</body>
</html>